🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / navigation / src / commonTest / kotlin / org / meshtastic / core / navigation / NavigationConfigTest.kt
Displaying Raw • Download
core/navigation/src/commonTest/kotlin/org/meshtastic/core/navigation/NavigationConfigTest.kt 520fa717a938fd84682403b41f57d9f7e1ef49ef (520fa717) Text, 9.00 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.navigation
Tff7b72import T7ee787androidx.navigation3.runtime.NavKey
Tff7b72import T7ee787androidx.savedstate.serialization.decodeFromSavedState
Tff7b72import T7ee787androidx.savedstate.serialization.encodeToSavedState
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertEquals
T8b949e/**
* Verifies that all route subclasses registered in [MeshtasticNavSavedStateConfig] can round-trip through SavedState
* serialization. This catches:
* - Missing `@Serializable` annotations on new route subclasses
* - Sealed interfaces not registered in [NavigationConfig.kt]
* - Breaking changes in the `subclassesOfSealed` experimental API
*/
Tff7b72class T56d364NavigationConfigTest Tb4b4b4{
T8b949e/**
* Every concrete route instance that can appear in a backstack. When adding a new route, add a representative
* instance here — the test will fail if serialization is misconfigured.
*/
Tff7b72private Tff7b72val Te6edf3allRouteInstancesTb4b4b4: Te6edf3ListTff7b72<Te6edf3NavKeyTff7b72> Tff7b72=
Te6edf3listOfTb4b4b4(
T8b949e// ChannelsRoute
Te6edf3ChannelsRouteTb4b4b4.Te6edf3ChannelsGraphTb4b4b4,
Te6edf3ChannelsRouteTb4b4b4.Te6edf3ChannelsTb4b4b4,
T8b949e// ConnectionsRoute
Te6edf3ConnectionsRouteTb4b4b4.Te6edf3ConnectionsGraphTb4b4b4,
Te6edf3ConnectionsRouteTb4b4b4.Te6edf3ConnectionsTb4b4b4,
T8b949e// ContactsRoute
Te6edf3ContactsRouteTb4b4b4.Te6edf3ContactsGraphTb4b4b4,
Te6edf3ContactsRouteTb4b4b4.Te6edf3ContactsTb4b4b4,
Te6edf3ContactsRouteTb4b4b4.Te6edf3MessagesTb4b4b4(Te6edf3contactKey Tff7b72= Ta5d6ff"Ta5d6fftest-contactTa5d6ff"Tb4b4b4, Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffhelloTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ContactsRouteTb4b4b4.Te6edf3MessagesTb4b4b4(Te6edf3contactKey Tff7b72= Ta5d6ff"Ta5d6fftest-contactTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ContactsRouteTb4b4b4.Te6edf3ShareTb4b4b4(Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffshare-textTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ContactsRouteTb4b4b4.Te6edf3QuickChatTb4b4b4,
T8b949e// MapRoute
Te6edf3MapRouteTb4b4b4.Te6edf3MapTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3MapRouteTb4b4b4.Te6edf3MapTb4b4b4(Te6edf3waypointId Tff7b72= T79c0ff4T79c0ff2Tb4b4b4)Tb4b4b4,
T8b949e// NodesRoute
Te6edf3NodesRouteTb4b4b4.Te6edf3NodesGraphTb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodesTb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailGraphTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3T79c0ff4Tb4b4b4)Tb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailGraphTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff5T79c0ff6T79c0ff7T79c0ff8Tb4b4b4)Tb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailTb4b4b4(Tb4b4b4)Tb4b4b4,
T8b949e// NodeDetailRoute
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3DeviceMetricsTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3PositionLogTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3EnvironmentMetricsTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3SignalMetricsTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3PowerMetricsTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3TracerouteLogTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3TracerouteMapTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3requestId Tff7b72= T79c0ff2T79c0ff0T79c0ff0Tb4b4b4, Te6edf3logUuid Tff7b72= Ta5d6ff"Ta5d6ffuuid-123Ta5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3TracerouteMapTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3requestId Tff7b72= T79c0ff2T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3HostMetricsLogTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3PaxMetricsTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3NodeDetailRouteTb4b4b4.Te6edf3NeighborInfoLogTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
T8b949e// SettingsRoute
Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsGraphTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsGraphTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff9T79c0ff9T79c0ff9Tb4b4b4)Tb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff9T79c0ff9T79c0ff9Tb4b4b4)Tb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3DeviceConfigurationTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3ModuleConfigurationTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3AdministrationTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3UserTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3ChannelConfigTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3DeviceTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3PositionTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3PowerTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3NetworkTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3DisplayTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3LoRaTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3BluetoothTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SecurityTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3MQTTTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SerialTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3ExtNotificationTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3StoreForwardTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3RangeTestTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3TelemetryTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3CannedMessageTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3AudioTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3RemoteHardwareTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3NeighborInfoTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3AmbientLightingTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3DetectionSensorTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3PaxcounterTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3StatusMessageTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3TrafficManagementTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3TAKTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3CleanNodeDbTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3DebugPanelTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3AboutTb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3FilterSettingsTb4b4b4,
T8b949e// FirmwareRoute
Te6edf3FirmwareRouteTb4b4b4.Te6edf3FirmwareGraphTb4b4b4,
Te6edf3FirmwareRouteTb4b4b4.Te6edf3FirmwareUpdateTb4b4b4,
T8b949e// WifiProvisionRoute
Te6edf3WifiProvisionRouteTb4b4b4.Te6edf3WifiProvisionGraphTb4b4b4,
Te6edf3WifiProvisionRouteTb4b4b4.Te6edf3WifiProvisionTb4b4b4(Te6edf3address Tff7b72= Ta5d6ff"Ta5d6ffAA:BB:CC:DD:EE:FFTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3WifiProvisionRouteTb4b4b4.Te6edf3WifiProvisionTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tf0883e@Test
Tff7b72fun Td2a8ff`all route instances round-trip through SavedState serialization`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3allRouteInstancesTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3route Tff7b72-Tff7b72>
Tff7b72val Te6edf3savedState Tff7b72= Te6edf3encodeToSavedStateTb4b4b4(Te6edf3routeTb4b4b4, Te6edf3MeshtasticNavSavedStateConfigTb4b4b4)
Tff7b72val Te6edf3decoded Tff7b72= Te6edf3decodeFromSavedStateTff7b72<Te6edf3NavKeyTff7b72>Tb4b4b4(Te6edf3savedStateTb4b4b4, Te6edf3MeshtasticNavSavedStateConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(
Te6edf3routeTb4b4b4,
Te6edf3decodedTb4b4b4,
Ta5d6ff"Ta5d6ffRound-trip failed for Tffd700${Te6edf3routeTff7b72::Te6edf3classTb4b4b4.Te6edf3simpleNameTffd700}Ta5d6ff: encoded Tffd700$Te6edf3routeTa5d6ff but decoded Tffd700$Te6edf3decodedTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ff`all sealed route interfaces are represented in the route instances list`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Verify we have at least one instance from each sealed route interface.
T8b949e// This catches the case where a new sealed interface is added to Routes.kt
T8b949e// but no instances are added to allRouteInstances above.
Tff7b72val Te6edf3representedInterfaces Tff7b72=
Te6edf3allRouteInstances
Tb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3route Tff7b72-Tff7b72>
Tff7b72when Tb4b4b4(Te6edf3routeTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3ChannelsRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffChannelsRouteTa5d6ff"
Tff7b72is Te6edf3ConnectionsRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffConnectionsRouteTa5d6ff"
Tff7b72is Te6edf3ContactsRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffContactsRouteTa5d6ff"
Tff7b72is Te6edf3MapRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffMapRouteTa5d6ff"
Tff7b72is Te6edf3NodesRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffNodesRouteTa5d6ff"
Tff7b72is Te6edf3NodeDetailRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffNodeDetailRouteTa5d6ff"
Tff7b72is Te6edf3SettingsRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffSettingsRouteTa5d6ff"
Tff7b72is Te6edf3FirmwareRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffFirmwareRouteTa5d6ff"
Tff7b72is Te6edf3WifiProvisionRoute Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffWifiProvisionRouteTa5d6ff"
Tff7b72else Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffUnknown(Tffd700${Te6edf3routeTff7b72::Te6edf3classTb4b4b4.Te6edf3simpleNameTffd700}Ta5d6ff)Ta5d6ff"
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3toSetTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3expectedInterfaces Tff7b72=
Te6edf3setOfTb4b4b4(
Ta5d6ff"Ta5d6ffChannelsRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffConnectionsRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffContactsRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffMapRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffNodesRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffNodeDetailRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffSettingsRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffFirmwareRouteTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffWifiProvisionRouteTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(
Te6edf3expectedInterfacesTb4b4b4,
Te6edf3representedInterfacesTb4b4b4,
Ta5d6ff"Ta5d6ffMissing sealed route interfaces in test coverage. Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffMissing: Tffd700${Te6edf3expectedInterfaces Tff7b72- Te6edf3representedInterfacesTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ff`route instances with default parameters serialize correctly`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Specifically test routes with nullable/default params to catch
T8b949e// serialization issues with optional fields.
Tff7b72val Te6edf3routesWithDefaultsTb4b4b4: Te6edf3ListTff7b72<Te6edf3PairTff7b72<Te6edf3NavKeyTb4b4b4, Te6edf3NavKeyTff7b72>Tff7b72> Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3MapRouteTb4b4b4.Te6edf3MapTb4b4b4(Tb4b4b4) Te6edf3to Te6edf3MapRouteTb4b4b4.Te6edf3MapTb4b4b4(Te6edf3waypointId Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailGraphTb4b4b4(Tb4b4b4) Te6edf3to Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailGraphTb4b4b4(Te6edf3destNum Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4,
Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailTb4b4b4(Tb4b4b4) Te6edf3to Te6edf3NodesRouteTb4b4b4.Te6edf3NodeDetailTb4b4b4(Te6edf3destNum Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsGraphTb4b4b4(Tb4b4b4) Te6edf3to Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsGraphTb4b4b4(Te6edf3destNum Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4,
Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsTb4b4b4(Tb4b4b4) Te6edf3to Te6edf3SettingsRouteTb4b4b4.Te6edf3SettingsTb4b4b4(Te6edf3destNum Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4,
Te6edf3WifiProvisionRouteTb4b4b4.Te6edf3WifiProvisionTb4b4b4(Tb4b4b4) Te6edf3to Te6edf3WifiProvisionRouteTb4b4b4.Te6edf3WifiProvisionTb4b4b4(Te6edf3address Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3routesWithDefaultsTb4b4b4.Te6edf3forEach Tb4b4b4{ Tb4b4b4(Te6edf3defaultInstanceTb4b4b4, Te6edf3explicitNullInstanceTb4b4b4) Tff7b72-Tff7b72>
Te6edf3assertEqualsTb4b4b4(
Te6edf3defaultInstanceTb4b4b4,
Te6edf3explicitNullInstanceTb4b4b4,
Ta5d6ff"Ta5d6ffDefault and explicit null should be equal for Tffd700${Te6edf3defaultInstanceTff7b72::Te6edf3classTb4b4b4.Te6edf3simpleNameTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3savedDefault Tff7b72= Te6edf3encodeToSavedStateTb4b4b4(Te6edf3defaultInstanceTb4b4b4, Te6edf3MeshtasticNavSavedStateConfigTb4b4b4)
Tff7b72val Te6edf3savedExplicit Tff7b72= Te6edf3encodeToSavedStateTb4b4b4(Te6edf3explicitNullInstanceTb4b4b4, Te6edf3MeshtasticNavSavedStateConfigTb4b4b4)
Tff7b72val Te6edf3decodedDefault Tff7b72= Te6edf3decodeFromSavedStateTff7b72<Te6edf3NavKeyTff7b72>Tb4b4b4(Te6edf3savedDefaultTb4b4b4, Te6edf3MeshtasticNavSavedStateConfigTb4b4b4)
Tff7b72val Te6edf3decodedExplicit Tff7b72= Te6edf3decodeFromSavedStateTff7b72<Te6edf3NavKeyTff7b72>Tb4b4b4(Te6edf3savedExplicitTb4b4b4, Te6edf3MeshtasticNavSavedStateConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3decodedDefaultTb4b4b4, Te6edf3decodedExplicitTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.07s